package com.xrh.core.annotation;


import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

/**
 * @function 枚举范围校验
 * @author 肖荣辉
 * @date 2023年12月8日
*/
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Repeatable(EnumValidation.List.class)
@Constraint(validatedBy = {EnumValidation.EnumValidator.class})
public @interface EnumValidation {
    String message() default "不在指定值域";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};


    /**
     * the enum's class-type
     *
     * @return Class
     */
    Class<?> value() default Void.class;

    /**
     * the method's name ,which used to validate the enum's value
     *
     * @return method's name
     */
    String method() default "name";


    //默认不允许为空
    boolean nullable() default false;

    /**
     * Defines several {@link EnumValidation} annotations on the same element.
     *
     * @see EnumValidation
     */
    @Documented
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
    @Retention(RUNTIME)
    @interface List {
        EnumValidation[] value();
    }

    class EnumValidator implements ConstraintValidator<EnumValidation, Object> {

        private EnumValidation annotation;

        @Override
        public void initialize(EnumValidation constraintAnnotation) {
            this.annotation = constraintAnnotation;
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            if (value == null) {
                if (annotation.nullable()) {
                    return true;
                } else {
                    //如果该字段不允许为空，则校验不通过
                    return false;
                }
            }
            Object[] objects = annotation.value().getEnumConstants();
            try {
                Method method = annotation.value().getMethod(annotation.method());
                for (Object o : objects) {
                    if (value.equals(method.invoke(o))) {
                        return true;
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return false;
        }
    }

}